package com.example.demo.component.osql;

import com.example.demo.component.osql.bean.osql_consts;
import com.example.demo.component.osql.bean.osql_param;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName osql_client
 * @Description
 * @date 2022/11/17 10:14
 * @Author yanceysong
 * @Version 1.0
 */
public class osql_client {
    public static final String CMD_PATH = "C:\\Windows\\System32\\cmd.exe";

    /**
     * 执行osql命令获取结果
     *
     * @param param     执行的参数
     * @param operation 对应的操作
     * @return 执行的结果
     */
    public String execute(osql_param param, Integer operation) {
        ArrayList<String> commands = new ArrayList<>();
        commands.add(get_command(param, operation));
        List<String> result = execute(commands);
        StringBuilder sb = new StringBuilder();
        for (String data : result) {
            sb.append(data).append("\n");
        }
        return sb.toString();
    }

    /**
     * 执行命令方法
     *
     * @param commands 指令的集合
     * @return 执行的结果
     */
    private List<String> execute(ArrayList<String> commands) {
        ArrayList<String> resultList = new ArrayList<>();
        Runtime run = Runtime.getRuntime();
        Process proc = null;
        PrintWriter out = null;
        BufferedReader in = null;
        try {
            proc = run.exec(CMD_PATH, null);
            if (proc != null) {
                in = new BufferedReader(new InputStreamReader(proc.getInputStream(), (String) System.getProperties().get("sun.jnu.encoding")));
                out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
                commands.forEach(out::println);
                out.println("exit");
                String line;
                while ((line = in.readLine()) != null) {
                    resultList.add(line);
                }
                proc.waitFor();
                in.close();
                out.close();
                proc.destroy();
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (proc != null) proc.destroy();
                if (in != null) in.close();
                if (out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultList;
    }

    /**
     * 获取bak文件当中的logical_name,不出意外应该是两个，一个是数据文件，一个是日志文件
     *
     * @param param 参数
     * @return logical_name的集合
     */
    private List<String> get_logical_name(osql_param param) {
        //            out.println("osql -U sa -P Oraps123 -S 172.21.1.20  -Q\"RESTORE FILELISTONLY from disk='D:/songyang666.bak'");
        StringBuilder builder = new StringBuilder();
        builder.append("osql -U ")
                .append(param.getUsername())
                .append(" -P ")
                .append(param.getPassword());
        if (param.getServer_ip() != null) {
            builder.append(" -S ")
                    .append(param.getServer_ip());
        }
        builder.append(" -Q\"RESTORE FILELISTONLY from disk='")
                .append(param.getBak_path())
                .append("'\"");
        ArrayList<String> commands = new ArrayList<>();
        commands.add(builder.toString());
        List<String> result = execute(commands);
        //由于打印的东西比较混乱，所以采用下面的方式进行过滤
        return result.stream().filter(data -> data.startsWith(" ") && !data.startsWith(" -") && !data.contains(" LogicalName")).collect(Collectors.toList());
    }

    /**
     * 根据参数获取osql的执行命令
     *
     * @param param     参数
     * @param operation 操作
     * @return 执行的命令
     */
    private String get_command(osql_param param, Integer operation) {
        switch (operation) {
            case 1:
                return get_sql_command(param);
            case 2:
                return get_backup_command(param);
            case 3:
                return get_restore_command(param);
            default:
                return "";
        }
    }

    /**
     * 获取执行SQL的命令
     *
     * @param param 参数
     * @return 命令
     */
    private String get_sql_command(osql_param param) {
        /* osql -U sa -P Oraps123 -S 172.21.1.20 -d yanceysong -i C:\Users\BG264\Desktop\【宋阳 所有数据库】create_sql_execute_record.sql*/
        if (!check(param, osql_consts.EXEC_SQL)) throw new RuntimeException("参数不正确");
        StringBuilder builder = new StringBuilder();
        builder.append("osql -U ")
                .append(param.getUsername())
                .append(" -P ")
                .append(param.getPassword());
        if (param.getServer_ip() != null) {
            builder.append(" -S ")
                    .append(param.getServer_ip());
        }
        builder.append(" -d ").append(param.getDatabase());
        builder.append(" -i ").append(param.getSql_path());
        return builder.toString();
    }

    /**
     * 根据参数获取备份数据库的命令
     *
     * @param param 参数
     * @return 命令
     */
    private String get_backup_command(osql_param param) {
        // osql -U sa -P Oraps123 -S 172.21.1.20 -d yanceysong -Q"BACKUP DATABASE yanceysong to disk='D:/songyang.bak'"
        if (!check(param, osql_consts.BACKUP)) throw new RuntimeException("参数不正确");
        StringBuilder builder = new StringBuilder();
        builder.append("osql -U ")
                .append(param.getUsername())
                .append(" -P ")
                .append(param.getPassword());
        if (param.getServer_ip() != null) {
            builder.append(" -S ")
                    .append(param.getServer_ip());
        }
        builder.append(" -Q\"BACKUP DATABASE ")
                .append(param.getDatabase())
                .append(" to disk='")
                .append(param.getBak_path())
                .append("'\"");
        return builder.toString();
    }

    /**
     * 获取还原数据库的命令
     *
     * @param param 参数
     * @return 执行命令
     */
    private String get_restore_command(osql_param param) {
        if (!check(param, osql_consts.RESTORE)) throw new RuntimeException("参数不正确");
        File file = new File(param.getRestore_path() + param.getDatabase() + "\\");
        if (!file.exists()) {
            boolean mkdirs = file.mkdirs();
            if (!mkdirs) throw new RuntimeException("创建恢复数据库文件夹失败，请检查权限或者路径");
        }
        String db_file = "";
        String db_log_file = "";
        List<String> logical_name = get_logical_name(param);
        if (logical_name.size() > 2) throw new RuntimeException("获取logical_name出错");
        for (String data : logical_name) {
            if (data.contains("log")) {
                db_log_file = data.trim();
                continue;
            }
            db_file = data.trim();
        }
        StringBuilder builder = new StringBuilder();
        builder.append("osql -U ")
                .append(param.getUsername())
                .append(" -P ")
                .append(param.getPassword());
        if (param.getServer_ip() != null) {
            builder.append(" -S ")
                    .append(param.getServer_ip());
        }
        builder.append(" -Q\"RESTORE DATABASE ")
                .append(param.getDatabase())
                .append(" from disk='")
                .append(param.getBak_path())
                .append("' WITH RECOVERY,REPLACE,MOVE '")
                .append(db_file).
                append("' to '")
                .append(param.getRestore_path())
                .append(param.getDatabase())
                .append(".mdf',MOVE '")
                .append(db_log_file)
                .append("' to '")
                .append(param.getRestore_path())
                .append(param.getDatabase())
                .append("_log.ldf'\"");
        return builder.toString();
    }

    /**
     * 检查参数是否符合标准
     *
     * @param param     参数
     * @param operation 操作
     * @return 检查结果
     */
    private Boolean check(osql_param param, Integer operation) {
        switch (operation) {
            case 1:
                return param.getUsername() != null && param.getPassword() != null && param.getSql_path() != null && param.getDatabase() != null;
            case 2:
                return param.getUsername() != null && param.getPassword() != null && param.getDatabase() != null && param.getBak_path() != null;
            case 3:
                return param.getUsername() != null && param.getPassword() != null && param.getDatabase() != null && param.getBak_path() != null && param.getRestore_path() != null;
        }
        return false;
    }
}
